package com.yeziji.security.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.fastjson2.JSONObject;
import com.yeziji.common.CommonSymbol;
import com.yeziji.constant.SecuritySal;
import com.yeziji.constant.VariousStrPool;
import com.yeziji.security.common.SecurityDbConfig;
import com.yeziji.security.common.reader.DbInfoReader;
import com.yeziji.utils.GzipUtils;
import com.yeziji.utils.RsaUtils;
import com.yeziji.utils.ScannerChain;

import javax.sql.DataSource;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.StringJoiner;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 数据源连接池配置
 *
 * @author hwy
 * @since 2023/11/13 21:47
 **/
public interface DynamicSecurityDbAuth {
    /**
     * 获取安全数据源
     *
     * @param securityDbConfig 数据源配置
     * @return {@link DataSource} 数据源
     */
    DataSource getSecurityDataSource(SecurityDbConfig securityDbConfig);

    /**
     * 将 securityDbConfig 的配置覆盖 dataSource
     *
     * @param securityDbConfig 安全配置
     * @param dataSource       数据源配置
     */
    default void copyProperties(SecurityDbConfig securityDbConfig, DruidDataSource dataSource) {
        if (securityDbConfig == null || dataSource == null) {
            return;
        }
        BeanUtil.copyProperties(securityDbConfig, dataSource, CopyOptions.create().setIgnoreNullValue(true));
    }

    /**
     * 自动填充数据信息
     *
     * <p>
     * 会根据对应项目的 security.db.info.path 配置去查找数据源文件位置，如果无配置则抛出异常；
     * 反之会去读取文件，如果文件不存在则会在项目启动时要求使用者进行初始化文件操作；
     * 如果文件存在，則读取文件配置进行赋值
     * </p>
     *
     * @param securityDbConfig 需要填充的数据信息
     */
    default void autoFillSecurityDbLoginInfo(SecurityDbConfig securityDbConfig, DbInfoReader dbInfoReader) {
        // 如果没有自定义填写数据信息，那么就需要去读取 db 文件
        if (securityDbConfig.isHasLoginDbInfo()) {
            return;
        }

        // 读取配置
        String path = dbInfoReader.getPath();
        if (StrUtil.isBlank(path)) {
            throw new IllegalArgumentException("生成失败~没有指定对应的数据读取目录");
        }

        // 初始化文件
        if (!FileUtil.exist(path)) {
            JSONObject json = new JSONObject();
            AtomicReference<String> dbType = new AtomicReference<>("mysql");
            ScannerChain.start()
                    .add("请输入数据源连接类型( mysql、postgresql 等……) ", dbType::set)
                    .add("请输入 jdbc-url: ", (jdbcUrl) -> {
                        String url = String.format("jdbc:%s://%s?", dbType.get(), jdbcUrl);
                        // 查看追加参数
                        Map<String, Object> defaultParams = dbInfoReader.getDefaultParams();
                        if (MapUtil.isNotEmpty(defaultParams)) {
                            StringJoiner sj = new StringJoiner(CommonSymbol.AND_SYMBOL);
                            for (Map.Entry<String, Object> entry : defaultParams.entrySet()) {
                                sj.add(String.format("%s=%s", entry.getKey(), entry.getValue()));
                            }
                            url += sj.toString();
                        }
                        securityDbConfig.setUrl(url);
                        json.put(VariousStrPool.MapKey.JDBC_URL, RsaUtils.privateEncrypt(url, SecuritySal.RsaKey.DB_PRIVATE_KEY));
                    })
                    .add("请输入 jdbc-username: ", (jdbcUsername) -> {
                        securityDbConfig.setUsername(jdbcUsername);
                        json.put(VariousStrPool.MapKey.JDBC_USERNAME, RsaUtils.privateEncrypt(jdbcUsername, SecuritySal.RsaKey.DB_PRIVATE_KEY));
                    })
                    .add("请输入 jdbc-password: ", (jdbcPwd) -> {
                        securityDbConfig.setPassword(jdbcPwd);
                        json.put(VariousStrPool.MapKey.JDBC_PASSWORD, RsaUtils.privateEncrypt(jdbcPwd, SecuritySal.RsaKey.DB_PRIVATE_KEY));
                    })
                    .end("初始化 securityDbInfo 成功");
            // 测试连接

            // 将数据库信息写入文件
            FileUtil.writeString(GzipUtils.compressToBase64Str(json.toJSONString()), new File(path), CommonSymbol.UTF8);
        }
        // 读取文件
        else {
            // 获取对应的字符串
            String dbInfoContent = FileUtil.readString(path, StandardCharsets.UTF_8);
            JSONObject json = JSONObject.parseObject(GzipUtils.uncompressByBase64Str(dbInfoContent));
            securityDbConfig.setUrl(RsaUtils.publicDecrypt(json.getString(VariousStrPool.MapKey.JDBC_URL), SecuritySal.RsaKey.DB_PUBLIC_KEY));
            securityDbConfig.setUsername(RsaUtils.publicDecrypt(json.getString(VariousStrPool.MapKey.JDBC_USERNAME), SecuritySal.RsaKey.DB_PUBLIC_KEY));
            securityDbConfig.setPassword(RsaUtils.publicDecrypt(json.getString(VariousStrPool.MapKey.JDBC_PASSWORD), SecuritySal.RsaKey.DB_PUBLIC_KEY));
        }
    }
}
